package com.wisezone.workflow.core.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

import com.wisezone.workflow.bean.WfActivity;
import com.wisezone.workflow.bean.WfActivityInstUser;
import com.wisezone.workflow.bean.WfActivityInstance;
import com.wisezone.workflow.bean.WfProcessInstance;
import com.wisezone.workflow.bean.WfVariable;
import com.wisezone.workflow.bean.WfVariableInstance;
import com.wisezone.workflow.bean.form.WfActivityInstanceForm;
import com.wisezone.workflow.bean.search.WfActivityInstanceSearch;
import com.wisezone.workflow.bean.search.WfActivitySearch;
import com.wisezone.workflow.core.ActivityInstance;
import com.wisezone.workflow.core.ProcessDefinition;
import com.wisezone.workflow.core.ProcessInstance;
import com.wisezone.workflow.exception.WfCoreException;

/**
 * 流程实例对象
 * 
 * @author tss 2009-09-05
 * 
 */
public class ProcessInstanceImpl extends BasePropertyImpl implements
		ProcessInstance {

	private WfProcessInstance wfProcessInstance;

	private ProcessDefinition processDefinition;

	private List<ActivityInstance> activityInstList;

	private Map<String, Object> variableMap = new HashMap<String, Object>();

	/**
	 * 构造方法
	 * 
	 * @param wfProcessInstance
	 * @param processDefinition
	 */
	public ProcessInstanceImpl(WfProcessInstance wfProcessInstance,
			ProcessDefinition processDefinition) {

		this.processDefinition = processDefinition;
		this.wfProcessInstance = wfProcessInstance;
		this.setDao(processDefinition);
	}

	/**
	 * 加载开始活动实例
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance loadStartActivityInstance() throws WfCoreException {

		try {
			return loadActivityInstance(ACTIVITY_DRAFT);

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 加载结束活动实例
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance loadEndActivityInstance() throws WfCoreException {

		try {
			return loadActivityInstance(ACTIVITY_END);

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 加载活动实例（根据ID）
	 * 
	 * @param id
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance loadActivityInstById(Long id)
			throws WfCoreException {

		if (id == null) {
			throw new IllegalArgumentException("活动实例ID不能为空");
		}
		try {

			WfActivityInstanceSearch searchEntity = new WfActivityInstanceSearch();
			searchEntity.setId(id);

			return selectActivityIntance(searchEntity);

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 获得流程实例下的所有活动
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public List<ActivityInstance> getActivityInstList() throws WfCoreException {

		try {
			this.activityInstList = getActivityInstList(new WfActivityInstanceSearch());

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
		return activityInstList;
	}
	
	/**
	 * 获得流程实例下的所有活动
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public List<ActivityInstance> getActivityInstList(WfActivityInstanceSearch search) throws WfCoreException {
		
		try {
			
			if(search == null){
				
				search = new WfActivityInstanceSearch();
			}
			search.setProcessInstId(this.getModel().getId());
			List<WfActivityInstance> list = this.getWfActivityInstanceDao()
			.listAll(search);
			
			this.activityInstList = new ArrayList<ActivityInstance>();
			for (Iterator<WfActivityInstance> it = list.iterator(); it
			.hasNext();) {
				
				WfActivityInstance ai = it.next();
				ActivityInstance activityInstance = new ActivityInstanceImpl(
						this, ai, this.getProcessDefinition().loadActivityById(
								ai.getActivityId()));
				
				this.activityInstList.add(activityInstance);
			}
			
		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
		return activityInstList;
	}

	/**
	 * 获得活动实例表单列表
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public List<WfActivityInstanceForm> getActivityInstFormList()
			throws WfCoreException {

		return this.getWfActivityInstanceDao().listByProcessInstId(
				this.getModel().getId());
	}

	/**
	 * 获得流程实例下的所有未开始的活动
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public List<ActivityInstance> getNotStartActivityInstList()
			throws WfCoreException {

		try {
			return getActivityInstList(getActivityInstState(ACTIVITY_INST_NOT_START)); // 未开始

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 获得流程实例下的所有已结束的活动
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public List<ActivityInstance> getEndedActivityInstList()
			throws WfCoreException {

		try {
			return getActivityInstList(getActivityInstState(ACTIVITY_INST_END));

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 流程启动
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessInstance start() throws WfCoreException {

		try {
			wfProcessInstance.setStartTime(new Date());
			wfProcessInstance.setState(getProcessInstState(PROCESS_INST_START)); // 已发起
			return this;

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 流程启动
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessInstance start(Map<String, Object> variableMap)
			throws WfCoreException {

		try {
			wfProcessInstance.setStartTime(new Date());
			wfProcessInstance.setState(getProcessInstState(PROCESS_INST_START)); // 已发起

			setProcessVariables(variableMap);

			return this;

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 流程结束
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessInstance end() throws WfCoreException {

		wfProcessInstance.setEndTime(new Date());
		wfProcessInstance.setState(getProcessInstState(PROCESS_INST_END)); // 结束

		// 结束该流程实例中未开始的活动实例
		List<ActivityInstance> activityInstList = getNotStartActivityInstList();
		for (Iterator<ActivityInstance> it = activityInstList.iterator(); it
				.hasNext();) {
			ActivityInstance ai = it.next();
			WfActivityInstance model = ai.getModel();
			model.setState(getActivityInstState(ACTIVITY_INST_END));
			model.setEndTime(new Date());
			ai.update(ai.getModel());
		}
		return this;
	}

	/**
	 * 流程暂停
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessInstance pause() throws WfCoreException {

		wfProcessInstance.setState(getProcessInstState(PROCESS_INST_PAUSE)); // 暂停状态
		return this;
	}

	/**
	 * 流程恢复
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessInstance resume() throws WfCoreException {

		wfProcessInstance.setState(getProcessInstState(PROCESS_INST_START)); // 已开始状态
		return this;
	}

	/**
	 * 设置流程启动人ID
	 * 
	 * @param starter
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessInstance setStarter(Long starter) throws WfCoreException {

		wfProcessInstance.setStarter(starter);
		return this;
	}

	/**
	 * 设置流程实例名称
	 * 
	 * @param starter
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessInstance setName(String name) throws WfCoreException {

		wfProcessInstance.setName(name);
		return this;
	}

	/**
	 * 设置流程实例备注
	 * 
	 * @param memo
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessInstance setMemo(String memo) throws WfCoreException {

		wfProcessInstance.setMemo(memo);
		return this;
	}

	/**
	 * 流程实例是否结束
	 */
	public boolean isEnd() throws WfCoreException {

		Long state = getProcessInstState(PROCESS_INST_END);
		return this.getModel().getState().equals(state);
	}

	/**
	 * 开始活动
	 * 
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance startActivityInstance() throws WfCoreException {

		try {
			WfActivitySearch searchEntity = new WfActivitySearch();
			searchEntity.setCategory(getActivityCategory(ACTIVITY_DRAFT)); // 起草节点
			searchEntity.setProcessDefId(this.getProcessDefinition().getModel()
					.getId());
			WfActivity wfActivity = getWfActivityDao().get(searchEntity);
			return createActivityInstance(wfActivity, null, null);

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 创建活动实例
	 * 
	 * @param searchEntity
	 * @param actorIds
	 * @param category
	 * @return
	 * @throws WfCoreException
	 */
	public ActivityInstance createActivityInstance(WfActivity wfActivity,
			Long[] actorIds, Long[] nextActorGroupIds) throws WfCoreException {

		if (wfActivity == null) {
			throw new IllegalArgumentException("活动实体不能为空");
		}
		try {

			// 创建活动对象
			WfActivityInstance ai = new WfActivityInstance();
			ai.setActivityId(wfActivity.getId());
			ai.setCreateTime(new Date());
			Long state = getActivityInstState(ACTIVITY_INST_NOT_START);
			ai.setState(state); // 未开始
			ai.setName(wfActivity.getName());
			ai.setProcessInstId(this.wfProcessInstance.getId());
			this.getWfActivityInstanceDao().save(ai);
			
			
			//创建活动持久对象
			ActivityInstance activityInstance = new ActivityInstanceImpl(this,
					ai, this.getProcessDefinition().loadActivityById(
							wfActivity.getId()));

			// 创建活动用户集合
			if (actorIds == null || actorIds.length == 0 || actorIds[0] == null) { // 没有设置参与用户就从配置文件中读取

				Object value = activityInstance.getVariable(ACTOR);
				if (value != null) {
					List<Long> actorList = new ArrayList<Long>();
					for (String s : value.toString().split(",")) {
						actorList.add(Long.valueOf(s));
					}
					actorIds = actorList.toArray(new Long[] {});
				}
			}

			if (actorIds != null) {
				for (Long actorId : actorIds) {

					WfActivityInstUser au = new WfActivityInstUser();
					au.setActivityInstId(ai.getId());
					au.setProcessInstId(this.wfProcessInstance.getId());
					au.setUserId(actorId);
					this.getWfActivityInstUserDao().save(au);
				}
			}

			// 创建活动用户组集合
			if (nextActorGroupIds == null || nextActorGroupIds.length == 0
					|| nextActorGroupIds[0] == null) { // 没有设置参与用户就从配置文件中读取

				Object value = activityInstance.getVariable(ACTOR_GROUP);
				if (value != null) {
					List<Long> actorList = new ArrayList<Long>();
					for (String s : value.toString().split(",")) {
						actorList.add(Long.valueOf(s));
					}
					nextActorGroupIds = actorList.toArray(new Long[] {});
				}
			}

			if (nextActorGroupIds != null) {
				for (Long actorId : nextActorGroupIds) {

					WfActivityInstUser au = new WfActivityInstUser();
					au.setActivityInstId(ai.getId());
					au.setProcessInstId(this.wfProcessInstance.getId());
					au.setUserGroupId(actorId);
					this.getWfActivityInstUserDao().save(au);
				}
			}


			return activityInstance;
		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}

	}

	/**
	 * 创建活动实例集合
	 * 
	 * @param searchEntity
	 * @param actorIds
	 * @param category
	 * @return
	 * @throws WfCoreException
	 */
	public List<ActivityInstance> createActivityInstList(
			WfActivitySearch searchEntity, Long[] actorIds,
			Long[] nextActorGroupIds) throws WfCoreException {

		if (searchEntity == null) {
			throw new IllegalArgumentException("活动参数对象不能为空");
		}
		try {

			// 获得活动对象
			List<WfActivity> list = this.getWfActivityDao().listAll(searchEntity);
			List<ActivityInstance> aiList = new ArrayList<ActivityInstance>();
			for (Iterator<WfActivity> it = list.iterator(); it.hasNext();) {
				WfActivity wfActivity = getWfActivityDao().get(searchEntity);
				ActivityInstance ai = createActivityInstance(wfActivity,
						actorIds, nextActorGroupIds);
				aiList.add(ai);
			}

			return aiList;

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}

	}

	/**
	 * 删除该流程下的活动实例
	 * 
	 * @param ai
	 * @throws WfCoreException
	 */
	public void delete(ActivityInstance ai) throws WfCoreException {

		if (ai == null) {
			throw new IllegalArgumentException("删除参数活动实例实体不能为空");
		}
		try {
			this.getWfActivityInstanceDao().delete(ai.getModel());

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 删除该流程下的活动实例集合
	 * 
	 * @param activityInstList
	 * @throws WfCoreException
	 */
	public void deleteList(List<ActivityInstance> activityInstList)
			throws WfCoreException {

		try {
			if (activityInstList != null) {
				for (Iterator<ActivityInstance> it = activityInstList
						.iterator(); it.hasNext();) {
					ActivityInstance activityInst = it.next();
					if (activityInst == null) {
						continue;
					}
					delete(it.next());
				}
			}

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 逻辑删除流程实例集合
	 * 
	 * @param userId
	 * @throws WfCoreException
	 */
	public void logicDelActivityInstList(Long userId) throws WfCoreException {

		if (userId == null) {
			throw new IllegalArgumentException("删除参数用户ID不能为空");
		}
		try {

			Long processInstId = this.getModel().getId();
			this.getWfActivityInstUserDao().logicDel(processInstId, userId);
		} catch (Exception e) {
			e.printStackTrace();
			throw new WfCoreException(e);
		}
	}

	/**
	 * 修改流程实例
	 * 
	 * @param wfProcessInstance
	 * @return
	 * @throws WfCoreException
	 */
	public ProcessInstance update(WfProcessInstance wfProcessInstance)
			throws WfCoreException {

		if (wfProcessInstance == null) {
			throw new IllegalArgumentException("修改参数流程实例实体不能为空");
		}
		try {
			this.getWfProcessInstanceDao().update(wfProcessInstance);
			this.setModel(wfProcessInstance);
			return this;

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 获得流程实例变量
	 */
	public Object getVariable(String name) throws WfCoreException {

		//变量名为空就直接返回null
		if (StringUtils.isEmpty(name)) {
			return null;
		}
		
		//处理引用变量
		WfVariable variableEntity = this.getWfVariableDao().getProcessEntity(this.getModel().getProcessDefId(), name);
		if(variableEntity != null){
			String value = variableEntity.getValue();
			if(value.startsWith("#")){   //值的格式如：#{apply},去掉#{} 处理
				if(value.indexOf(",") != -1){
					String [] values = value.split(",");
					value = "";
					for(String val : values){
						if(StringUtils.isEmpty(val)){
							continue;
						}
						name = val.substring(2,val.length()-1);
						value += "," + getVariable(name);
					}
					if(!value.equals("")){
						return value.substring(1);
					}
				}else{
					name = value.substring(2,value.length()-1);
				}
			}
		}
		
		/**
		 * 变量查找顺序
		 * 1：变量功能作用域中 variableMap
		 * 2：当前流程实例中
		 * 3：当前流程实例模板中
		 * 4：原型模板中
		 */
		// 作用域1
		if (variableMap.containsKey(name)) {
			return variableMap.get(name);
		}
		//作用域2 
		WfVariableInstance entity = this.getWfVariableInstanceDao()
				.getEntityByProcessInstId(name, this.getModel().getId());
		if (entity != null) {
			return entity.getValue();
		} 
		//作用域3
		entity = this.getWfVariableInstanceDao()
		.getEntityByProcessDefId(name, this.getModel().getProcessDefId());
		if (entity != null) {
			return entity.getValue();
		} 
		//作用域4
		variableEntity = this.getWfVariableDao().getProcessEntity(this.getModel().getProcessDefId(),
				name);
		if(variableEntity != null){
			String varValue = variableEntity.getValue();
			while(StringUtils.isNotEmpty(varValue) && varValue.startsWith("#")){    //递归查找
				variableEntity = this.getWfVariableDao().getProcessEntity(this.getModel().getProcessDefId(),
						name);
				if(variableEntity != null){
					varValue = variableEntity.getValue();
				}
			}
			if(StringUtils.isNotEmpty(varValue) && !varValue.startsWith("#")){
				return varValue;
			}
		}
			
		//都没有找到
		if(log.isDebugEnabled()){
			log.debug("没有找到" + name + "变量 ,在 processInstId = "
					+ this.getModel().getId());
		}
		return null;

	}

	/**
	 * 设置流程实例变量
	 * 
	 * @param name
	 * @param value
	 * @throws WfCoreException
	 */
	public void setVariable(String name, String value) throws WfCoreException {

		if (StringUtils.isEmpty(name)) {
			throw new IllegalArgumentException("参数流程实例变量名不能为空");
		}
		WfVariableInstance entity = this.getWfVariableInstanceDao()
				.getEntityByProcessInstId(name, getModel().getId());
		if (entity == null) { // 新增
			entity = new WfVariableInstance();
			entity.setProcessInstId(getModel().getId());
			entity.setName(name);
			entity.setValue(value);
		} else { // 修改
			entity.setValue(value);
		}
		this.getWfVariableInstanceDao().saveOrUpdate(entity);

	}

	/**
	 * 加载各类型的活动
	 * 
	 * @param category
	 * @return
	 * @throws WfCoreException
	 */
	private ActivityInstance loadActivityInstance(String category)
			throws WfCoreException {

		try {

			WfActivityInstanceSearch searchEntity = new WfActivityInstanceSearch();

			searchEntity.setProcessInstId(wfProcessInstance.getId());
			// searchEntity.setActivityId(activityId); //暂设
			WfActivityInstance ai = this.getWfActivityInstanceDao().get(
					searchEntity);

			ActivityInstance activityInstance = new ActivityInstanceImpl(this,
					ai, this.getProcessDefinition().loadActivityById(
							ai.getActivityId()));

			return activityInstance;

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/**
	 * 查询活动实例(条件 id,name)
	 * 
	 * @param wfActivity
	 * @return
	 * @throws WfCoreException
	 */
	private ActivityInstance selectActivityIntance(
			WfActivityInstanceSearch searchEntity) throws WfCoreException {

		if (searchEntity == null) {
			throw new IllegalArgumentException("参数活动实例对象不能为空");
		}
		try {

			WfActivityInstance wfActivityInstance = getWfActivityInstanceDao()
					.get(searchEntity);
			ActivityInstance activityInstance = new ActivityInstanceImpl(this,
					wfActivityInstance, this.getProcessDefinition()
							.loadActivityById(
									wfActivityInstance.getActivityId()));
			return activityInstance;

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}

	}

	/**
	 * 获得流程实例下的所有已结束的活动
	 * 
	 * @param state
	 *            0:未开始； 1：已结束;2:已开始
	 * @return
	 * @throws WfCoreException
	 */
	private List<ActivityInstance> getActivityInstList(Long state)
			throws WfCoreException {

		if (state == null) {
			throw new IllegalArgumentException("参数活动实例状态不能为空");
		}
		List<ActivityInstance> list = new ArrayList<ActivityInstance>();
		try {
			if (this.activityInstList == null) {
				activityInstList = getActivityInstList();
			}
			for (Iterator<ActivityInstance> it = this.activityInstList
					.iterator(); it.hasNext();) {
				ActivityInstance activityInstance = it.next();
				WfActivityInstance ai = activityInstance.getModel();
				if (state.equals(getActivityInstState(ACTIVITY_INST_NOT_START))
						&& ai.getStartTime() == null) {
					list.add(activityInstance);
				} else if (state
						.equals(getActivityInstState(ACTIVITY_INST_END))
						&& ai.getEndTime() != null) {
					list.add(activityInstance);
				}else if (state
						.equals(getActivityInstState(ACTIVITY_INST_START))
						&& ai.getEndTime() == null) {
					list.add(activityInstance);
				}
			}

		} catch (WfCoreException e) {
			e.printStackTrace();
			throw e;
		}
		return list;
	}
	
	/**
	 * 设置流程变量实例
	 * @param variableMap
	 * @throws WfCoreException
	 */
	private void setProcessVariables(Map<String, Object> globalVariableMap) throws WfCoreException{
		
		
		if(globalVariableMap == null){
			return;
		}
		
		// 获得流程程变量实例
		List<WfVariable> wfVariableList = getWfVariableDao()
				.getProcessVariableList(
						processDefinition.getModel().getId());

		try {
			
			Set<String> set = globalVariableMap.keySet();
			for (Iterator<String> iter = set.iterator(); iter.hasNext();) { // 遍历参数值
				
				String key = iter.next();
				String name = null;
				for (Iterator<WfVariable> it = wfVariableList.iterator(); it
				.hasNext();) { // 遍历流程变量
					WfVariable entity = it.next();
					name = entity.getName();
					if (name.equals(key)) {
						break;
					}
				}
				
				Object obj = globalVariableMap.get(key);
				String variableValue = "";
				
				// 前台传过来的参数进行转换
				if (obj instanceof Long[]) {
					Long[] ls = (Long[]) obj;
					for (Long l : ls) {
						variableValue += ","+l.toString();
					}
					if(!variableValue.equals("")){
						variableValue = variableValue.substring(1);
					}
				} else if (obj instanceof String[]) {
					String[] ss = (String[]) obj;
					for (String s : ss) {
						variableValue += ","+s;
					}
					if(!variableValue.equals("")){
						variableValue = variableValue.substring(1);
					}
				} else {
					variableValue = obj.toString();
				}
				
				// 构建流程实例变量实例
				WfVariableInstance wfVariableInst = new WfVariableInstance();
				wfVariableInst.setProcessInstId(wfProcessInstance.getId());
				wfVariableInst.setName(key);
				wfVariableInst.setValue(variableValue);
				this.getWfVariableInstanceDao().save(wfVariableInst);
				
				// 覆盖设置
				variableMap.put(wfVariableInst.getName(), wfVariableInst
						.getValue());
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new WfCoreException("流程变量实例保存失败");
		}
		
	}

	public ProcessDefinition getProcessDefinition() {
		return processDefinition;
	}

	public void setProcessDefinition(ProcessDefinition processDefinition) {
		this.processDefinition = processDefinition;
	}

	public WfProcessInstance getModel() {
		return wfProcessInstance;
	}

	public void setModel(WfProcessInstance wfProcessInstance) {
		this.wfProcessInstance = wfProcessInstance;
	}

}
